package com.smart.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.smart.common.Constants;
import com.smart.common.PageInfo;
import com.smart.common.enums.ItemTypeEnum;
import com.smart.common.enums.SuperviseModuleEnum;
import com.smart.common.service.LogService;
import com.smart.common.utils.AssertUtil;
import com.smart.context.SessionContext;
import com.smart.mapper.*;
import com.smart.model.convert.ProjectConvert;
import com.smart.model.domain.*;
import com.smart.model.dtomapper.ProjectReportDtoMapper;
import com.smart.model.dtomapper.ProjectWeeklyItemDtoMapper;
import com.smart.model.dtomapper.ProjectWeeklyTaskDtoMapper;
import com.smart.model.request.*;
import com.smart.model.vo.ProjectReportVO;
import com.smart.model.vo.ProjectVO;
import com.smart.model.vo.ProjectWeeklyItemVO;
import com.smart.service.ProjectItemService;
import com.smart.service.ProjectReportService;
import com.smart.service.ProjectWeeklyItemService;
import com.smart.service.ProjectWeeklyTaskService;
import com.smart.utils.SplitTimeRangeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zhanghong
 */
@Slf4j
@Service
public class ProjectWeeklyTaskServiceImpl extends ServiceImpl<ProjectWeeklyTaskMapper, ProjectWeeklyTaskDO> implements ProjectWeeklyTaskService {
    @Autowired
    private ProjectWeeklyTaskMapper projectWeeklyTaskMapper;
    @Autowired
    private ProjectItemService projectItemService;
    @Autowired
    private ProjectWeeklyItemService projectWeeklyItemService;
    @Autowired
    private ProjectWeeklyItemMapper projectWeeklyItemMapper;
    @Autowired
    private ProjectReportService projectReportService;
    @Autowired
    private ProjectReportMapper projectReportMapper;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private LogService logService;
    @Autowired
    private StreetMapper streetMapper;
    @Autowired
    private JiansheProjectMapper jiansheProjectMapper;
    @Autowired
    private ManageUserRegistrationMapper registrationMapper;

    /**
     * 统计范围
     * 1.该周报任务下已提报+未提报（项目状态为：在施、完工待验）的数据
     * @param request
     * @return
     */
    @Override
    public PageInfo<ProjectVO> pageQuery(ProjectWeeklyTaskRequest request) {
        AssertUtil.assertNotNull(request.getYear(), "年份不能为空");
        AssertUtil.assertNotNull(request.getWeekNum(), "周数不能为空");
        //查询周报任务模板
        ProjectWeeklyTaskDO taskDO = projectWeeklyTaskMapper.queryByYearAndWeek(request.getYear().intValue(), request.getWeekNum().intValue());
        if (taskDO == null) {
            return PageInfo.buildEmpty();
        }
        // 建设单位只能看到当前所关联项目的提报数据
        if (SessionContext.getJiansheUnitId() != null) {
            List<Long> relationProjectList = jiansheProjectMapper.selectAllProjectId(SessionContext.getJiansheUnitId());
            if (CollectionUtils.isEmpty(relationProjectList)) {
                log.info("当前建设单位未关联任何项目");
                return PageInfo.buildEmpty();
            }
            request.setProjectIds(relationProjectList);
        }

        //查询提报数据
        ProjectReportStatisticsRequest req = new ProjectReportStatisticsRequest();
        req.setTaskId(taskDO.getId());
        req.setProjects(request.getProjectIds());
        req.setReportStatus(1);
        req.setStreetCode(request.getStreetCode());
        req.setConstructionStatus(request.getProjectStatus());
        req.setKeyWord(request.getKeyWord());
        List<ProjectDO> projects = projectReportMapper.listEffectProjectByCondition(req);

        // 内存分页
        int count = projects.size();
        List<ProjectDO> page = ListUtil.page(request.getPageNum() - 1, request.getPageSize(), projects);
        List<ProjectVO> projectVOS = ProjectConvert.buildProjectVoList(page);
        projectVOS = projectVOS.stream().map(item->{
            item.setWeeklyTaskId(taskDO.getId());
            item.setPersonCount(registrationMapper.selectProjectPersonCount(item.getId()));
            return item;
        }).collect(Collectors.toList());
        return PageInfo.build(request.getPageNum(), request.getPageSize(), projectVOS, count, getExtInfoMap(taskDO.getId(), req.getProjects()));
    }

    /**
     * 统计范围
     * 1.该周报任务下未提报（项目状态为：在施、完工待验）的数据
     * @param request
     * @return
     */
    @Override
    public PageInfo<ProjectVO> unReportPageQuery(ProjectWeeklyTaskRequest request) {
        // 前置校验
        AssertUtil.assertNotNull(request.getYear(), "年份不能为空");
        AssertUtil.assertNotNull(request.getWeekNum(), "周数不能为空");
        ProjectWeeklyTaskDO taskDO = projectWeeklyTaskMapper.queryByYearAndWeek(request.getYear().intValue(), request.getWeekNum().intValue());
        if (taskDO == null) {
            log.info("任务不存在");
            return PageInfo.buildEmpty();
        }

        // 建设单位只能看到当前所关联项目的提报数据
        if (SessionContext.getJiansheUnitId() != null) {
            List<Long> relationProjectList = jiansheProjectMapper.selectAllProjectId(SessionContext.getJiansheUnitId());
            if (CollectionUtils.isEmpty(relationProjectList)) {
                log.info("当前建设单位未关联任何项目");
                return PageInfo.buildEmpty();
            }
            request.setProjectIds(relationProjectList);
        }

        //查询提报数据
        ProjectReportStatisticsRequest req = new ProjectReportStatisticsRequest();
        req.setTaskId(taskDO.getId());
        req.setProjects(request.getProjectIds());
        req.setReportStatus(request.getReportStatus());
        req.setStreetCode(request.getStreetCode());
        req.setConstructionStatus(request.getProjectStatus());
        req.setKeyWord(request.getKeyWord());
        List<ProjectDO> projects = projectReportMapper.listEffectProjectByCondition(req);

        // 内存分页
        int count = projects.size();
        List<ProjectDO> page = ListUtil.page(request.getPageNum() - 1, request.getPageSize(), projects);
        List<ProjectVO> projectVOS = ProjectConvert.buildProjectVoList(page);
        return PageInfo.build(request.getPageNum(), request.getPageSize(), projectVOS, count, getExtInfoMap(taskDO.getId(), req.getProjects()));
    }

    /**
     * 获取统计信息
     * @param taskId
     * @param projects
     * @return
     */
    private Map<String, Object> getExtInfoMap(Long taskId, List<Long> projects) {
        Set<Long> projectSet = Sets.newHashSet();
        if (projects != null) {
            projectSet = Sets.newHashSet(projects);
        }
        //已提报数据
        Long reportNum = projectReportMapper.reportCountRangeProject(taskId, projectSet);
        //未提报数据[也只统计，在施和完工待验的项目数据]
        Long unReportNum = projectReportMapper.unReportCountRangeProject(taskId, projectSet);
        Map<String, Object> extInfo = Maps.newHashMap();
        extInfo.put(Constants.KEY_SHOULD_REPORT_NUM, reportNum + unReportNum);
        extInfo.put(Constants.KEY_UN_REPORT_NUM, unReportNum);
        return extInfo;
    }

    @Override
    public PageInfo<ProjectWeeklyItemVO> pageListItem(ProjectWeeklyItemPageRequest request) {
        return projectWeeklyItemService.pageItemQuery(request);
    }

    @Override
    public String weeklyReportFileType(ProjectWeeklyItemPageRequest request) {
        List<ProjectWeeklyItemDO> projectWeeklyItemDOS = projectWeeklyItemMapper.listItemQuery(request);
        long count = projectWeeklyItemDOS.stream().filter(item -> item.getItemType().equals(ItemTypeEnum.IMAGE.name())).count();
        if (count > 0) {
            return "ZIP";
        }
        return "EXCEL";
    }

    @Override
    public Boolean add(ProjectWeeklyTaskRequest request) {
        ProjectWeeklyTaskDO projectWeeklyTaskDO = ProjectWeeklyTaskDtoMapper.INSTANCE.request2DO(request);
        save(projectWeeklyTaskDO);
        return true;
    }

    @Override
    public Boolean updateByKey(ProjectWeeklyTaskRequest request) {
        ProjectWeeklyTaskDO projectWeeklyTaskDO = ProjectWeeklyTaskDtoMapper.INSTANCE.request2DO(request);
        save(projectWeeklyTaskDO);
        return true;
    }

    @Override
    public Boolean deleteByKey(long id) {
        projectWeeklyTaskMapper.deleteDOById(id);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addItem(ProjectWeeklyItemAddRequest request) {
        valid(null, request.getStartTime(), request.getEndTime());

        ProjectWeeklyItemDO projectItemDO = new ProjectWeeklyItemDO();
        projectItemDO.setName(request.getName());
        projectItemDO.setItemType(request.getItemType());
        projectItemDO.setTextMaxLength(request.getTextMaxLength());
        projectItemDO.setImageNum(request.getImageNum());
        projectItemDO.setSortNum(request.getSortNum());
        projectItemDO.setStartTime(request.getStartTime());
        Date endTime = DateUtil.endOfDay(request.getEndTime()).offset(DateField.SECOND, -1).toJdkDate();
        projectItemDO.setEndTime(endTime);
        projectWeeklyItemService.save(projectItemDO);

        //记录操作日志
        String afterContent = JSON.toJSONString(projectItemService.getById(projectItemDO.getId()));
        logService.logSupervisePlatformAddScene(SuperviseModuleEnum.信息填报项, projectItemDO.getId(), afterContent);
        return true;
    }

    @Override
    public Boolean updateItem(ProjectItemUpdateRequest request) {
        valid(request.getId(), request.getStartTime(), request.getEndTime());
        ProjectWeeklyItemDO byId = projectWeeklyItemService.getById(request.getId());
        ProjectWeeklyItemDO weeklyItemDO = ProjectWeeklyItemDtoMapper.INSTANCE.request2DO(request);
        Date date = DateUtil.endOfDay(request.getEndTime()).offset(DateField.SECOND, -1).toJdkDate();
        weeklyItemDO.setEndTime(date);
        projectWeeklyItemService.saveOrUpdate(weeklyItemDO);

        //记录操作日志
        String beforeContent = JSON.toJSONString(byId);
        String afterContent = JSON.toJSONString(projectItemService.getById(weeklyItemDO.getId()));
        logService.logSupervisePlatformUpdateScene(SuperviseModuleEnum.信息填报项, weeklyItemDO.getId(), beforeContent, afterContent);
        return true;
    }

    @Override
    public ProjectReportVO getReportDetail(WeeklyReportDetailRequst request) {
        AssertUtil.assertNotNull(request.getWeeklyTaskId(), "项目周报任务id不能为空");
        AssertUtil.assertNotNull(request.getProjectId(), "项目id不能为空");

        ProjectReportDO reportDO = projectReportService.lambdaQuery()
                .eq(ProjectReportDO::getTaskId, request.getWeeklyTaskId())
                .eq(ProjectReportDO::getProjectId, request.getProjectId())
                .one();

        ProjectReportVO projectReportVO = ProjectReportDtoMapper.INSTANCE.do2VO(reportDO);
        fillInfo(projectReportVO);
        return projectReportVO;
    }

    /**
     * 填充信息
     * @param projectReportVO
     */
    private void fillInfo(ProjectReportVO projectReportVO) {
        //周报信息
        ProjectWeeklyTaskDO projectWeeklyTaskDO = projectWeeklyTaskMapper.selectDOById(projectReportVO.getTaskId());
        if (projectWeeklyTaskDO != null) {
            projectReportVO.setYear(projectWeeklyTaskDO.getYear());
            projectReportVO.setWeek(projectWeeklyTaskDO.getWeekNum());
        }

        //项目信息
        ProjectDO projectDO = projectMapper.selectDOById(projectReportVO.getProjectId());
        if (projectDO != null) {
            projectReportVO.setProjectName(projectDO.getProjectName());
            projectReportVO.setProjectNumber(projectDO.getProjectNumber());
            projectReportVO.setConstructionStatus(projectDO.getConstructionStatus());
            projectReportVO.setStreetCode(projectDO.getStreetCode());
            projectReportVO.setAddress(projectDO.getAddress());
            projectReportVO.setEngineeringType(projectDO.getEngineeringType());
            projectReportVO.setQualityRegistrationNumber(projectDO.getQualityRegistrationNumber());
            projectReportVO.setShigongUnit(projectDO.getShigongUnit());
        }

        //街道信息
        StreetDO streetDO = streetMapper.selectDOByCode(projectDO.getStreetCode());
        if (streetDO != null) {
            projectReportVO.setStreetName(streetDO.getName());
        }
    }

    /**
     * 校验周对应填报数是否超过100项
     */
    private void valid(Long id, Date startTime, Date endTime) {
        //将当前填报开始时间和结束时间按周期分割成数组
        List<Pair<Date, Date>> pairList = SplitTimeRangeUtil.splitTimeRange(startTime, DateUtil.endOfDay(endTime));
        for (Pair<Date, Date> pair : pairList) {
            Integer count = projectWeeklyItemMapper.countOver(id, pair.getLeft(), pair.getRight());
            AssertUtil.assertTrue(count < 100, "[当前配置的生效时间中已达到100项生效的时间范围]项目需配置的信息项已达100项，不可继续添加。");
        }
    }
}
